/*
 * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 *
 * This file is part of Harmattan SmashMiner OpenGL game application.
 * 
 * Harmattan SmashMiner OpenGL Example Application version 1.0.0
 *  
 * Latest update: 15.4.2011
 *
 * The Harmattan SmashMiner OpenGL example application demonstrates how to use 
 * the OpenGL ES in Harmattan devices.
 *
 * This example is provided as a starting point for 3rd party
 * developers (you) to ease the implementation of OpenGL based 
 * games. Ideas, parts of code or methodologies that this
 * example application uses can be freely used without restrictions.
 *
 * See file README.txt how to build and compile this example application
 * in the Harmattan SDK environment. 
 * 
 * See file INSTALL.txt to find out what is required to run this
 * application and how to install the application to the device or
 * alternatively in QEMU-emulator.
 *
 * The LICENSE.txt file explains the license this software is provided
 * with. A copy of the same license is included in this source file.
 * 
 */

/*
 * Copyright (C) 2011 by Nokia Corporation.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "timermanager.h"
#include "visualeffectdata.h"

#include <QDebug>

/*! \class TimerManager
 *
 * \brief \c TimerManager class instance is used for managing all the game timers for animation, game
 * states, effects etc.
 *
 * Game timers are instances of \c GameTimer class.
 * When instantiating a \c TimerManager it creates instances of all the timers and stores them into a 
 * \c timers vector. \c TimerManager is used for starting, stopping and reseting timers and for requesting timer states.
 * It also provides methods for requesting timer states (is timer active or is full time, half time or 
 * first/last quarter time reached) and for reseting timers and cleaning effect data.
 *
 * Singleton design pattern is used at TimerManager to ensure that only one instance exists.
 *
 * \c TimerManager contains pointer for hyper jump and bomb effect data. The timer lengths are defined as enumeration value.
 *
 * Instantiating \c TimerManager:
 * \code
 * TimerManager *timerManager = TimerManager::getInstance();
 * \endcode
 *
 *
 * Starting a timer:
 * \code
 * timerManager->startGameTimer(GameTimer::stateGetReadyTimer);
 * \endcode
 *
 * Checking if timer is active (running but not yet finished):
 * \code
 * if (timerManager->isActive(GameTimer::stateGetReadyTimer)) {
 *      // ...
 * }
 * \endcode
 *
 * Updating running timers:
 * \code
 * timerManager->updateTimers(timestep);
 * \endcode
 *
 * Checking if full time is reached (this is one-shot, true is returned only once when full time
 * has passed):
 * \code
 * if (timerManager->isFullTime(GameTimer::stateGetReadyTimer)) {
 *    // ...
 * }
 * \endcode
 *
 * Stopping a timer:
 * \code
 * timerManager->stopGameTimer(GameTimer::stateGetReadyTimer);
 * \endcode
 *
 * Resetting the timers and cleaning up the effect data. 
 * \code
 * timerManager->resetTimers();
 * timerManager->cleanData();
 * \endcode
 */


TimerManager *TimerManager::instance = NULL;

/*! Used to store hyper jump effect data */
HyperJumpEffectData *TimerManager::hyperJumpOutData = NULL;
/*! Used to store hyper jump effect data */
HyperJumpEffectData *TimerManager::hyperJumpInData = NULL;

/*! Used to store bomb effect data */
BombEffectData *TimerManager::bombEffectData = NULL;

/*  
 *  \brief Constructor of \c TimerManager class.
 *
 *  Instantiates all the game timers and stores pointers to timers to \c vector.
 *
 *  \param parent Parent object
*/
TimerManager::TimerManager(QObject *parent) 
    : QObject(parent)
    , timers(GameTimer::NumTimers)
{
    timers[GameTimer::stateGetReadyTimer] 
        = new GameTimer(GameTimer::stateGetReadyTimer, GetReadyCount, this);
    timers[GameTimer::stateLevelChangingTimer] 
        = new GameTimer(GameTimer::stateLevelChangingTimer, LevelChangingCount, this);
    timers[GameTimer::statePlayerCrashedTimer] 
        = new GameTimer(GameTimer::statePlayerCrashedTimer, PlayerCrashedCount, this);
    timers[GameTimer::stateGameOverTimer] 
        = new GameTimer(GameTimer::stateGameOverTimer, GameOverCount, this);

    timers[GameTimer::shipSafeTimer] 
        = new GameTimer(GameTimer::shipSafeTimer, 500, this);
    timers[GameTimer::shipBall2ConeTimer] 
        = new GameTimer(GameTimer::shipBall2ConeTimer, ShipModeCount, this);
    timers[GameTimer::shipCone2BallTimer] 
        = new GameTimer(GameTimer::shipCone2BallTimer, ShipModeCount, this);

    timers[GameTimer::hyperJumpOutTimer] 
        = new GameTimer(GameTimer::hyperJumpOutTimer, HyperJumpCount, this);
    timers[GameTimer::hyperJumpInTimer] 
        = new GameTimer(GameTimer::hyperJumpInTimer, HyperJumpCount, this);
    timers[GameTimer::bombEffectTimer] 
        = new GameTimer(GameTimer::bombEffectTimer, BombEffectCount, this);

    timers[GameTimer::moreObjectsTimer]
        = new GameTimer(GameTimer::moreObjectsTimer, 500, this);
}

/*!
 * Destructor of TimerManager class
 *
 * Cleans up all the statically stored effect data.
 */
TimerManager::~TimerManager()
{
    cleanData();
}

/*! Provides instance of \c TimerManager class, creates a new instance if an existing instance is not 
 * available.
 *
 * \return A \c TimerManager instance
 */
TimerManager * TimerManager::getInstance()
{
    if (instance != NULL) {
        return instance;
    } else {
        instance = new TimerManager();
        return instance;
    }
}

/*! Starts a game timer of given type with given start time. If no start time is provided will
 * start the timer from 0.
 *
 * \param type  One of \c GameTimer::TimerType game timer enumeration types
 * \param startTime The timer start time in milliseconds
 */
void TimerManager::startGameTimer(GameTimer::TimerType type, int startTime)
{
    timers[type]->start(startTime);
}

/*!
 * Stops the game timer of give type.
 *
 * \param type One of \c GameTimer::TimerType game timer enumeration types
 */
void TimerManager::stopGameTimer(GameTimer::TimerType type)
{
    timers[type]->stop();
}

/*!
 * Increments all the running timers with given time step.
 *
 * \param timestep An increment to timers in milliseconds.
 */
void TimerManager::updateTimers(int timestep)
{
    for (int i = 0; i < timers.size(); ++i)
        timers[i]->incTime(timestep);
}

/*! Queries if a timer of given type is started but not reached full time.
 *
 * \param type One of \c GameTimer::TimerType game timer enumeration types
 */
bool TimerManager::isActive(GameTimer::TimerType type)
{
    return timers.at(type)->isActive();
}

/*! For querying if the first quarter time of a given timer type is reached. 
 *
 * Note: This is works as a ''one-shot'' method for each timer run. When the first
 * quarter time has been reached, true will be returned only the first time asked.
 *
 * \param type One of \c GameTimer::TimerType game timer enumeration types
 * \return Returns true once when the first quarter time of given timer type has passed
 */
bool TimerManager::isFirstQuarterTime(GameTimer::TimerType type)
{
    return timers.at(type)->isFirstQuarterTime();
}

/*! For querying if the half time of a given timer type is reached. 
 *
 * Note: This is works as a ''one-shot'' method for each timer run. When the 
 * half time has been reached, true will be returned only the first time asked.
 *
 * \param type One of \c GameTimer::TimerType game timer enumeration types
 * \return Returns true once when the half time of given timer type has passed
 */
bool TimerManager::isHalfTime(GameTimer::TimerType type)
{
    return timers.at(type)->isHalfTime();
}

/*! For querying if the last quarter time of a given timer type is reached. 
 *
 * Note: This is works as a ''one-shot'' method for each timer run. When the last 
 * quarter time has been reached, true will be returned only the first time asked.
 *
 * \param type One of \c GameTimer::TimerType game timer enumeration types
 * \return Returns true once when the last quarter time of given timer type has passed
 */
bool TimerManager::isLastQuarterTime(GameTimer::TimerType type)
{
    return timers.at(type)->isLastQuarterTime();
}

/*! For querying if the full time of a given timer type is reached. 
 *
 * Note: This is works as a ''one-shot'' method for each timer run. When the 
 * full time has been reached, true will be returned only the first time asked.
 *
 * \param type One of \c GameTimer::TimerType game timer enumeration types
 * \return Returns true once when the full time of given timer type has passed
 */
bool TimerManager::isFullTime(GameTimer::TimerType type)
{
    return timers.at(type)->isFullTime();
}

/*! The current time of timer of given type
 *
 * \param type One of \c GameTimer::TimerType game timer enumeration types
 * \return Current running time of the timer of given type. 
 */
int TimerManager::time(GameTimer::TimerType type)
{
    return timers.at(type)->time();
}

/*! The timer length --- the ending time of timer of given type.
 *
 * \param type One of \c GameTimer::TimerType game timer enumeration types
 * \return Length of the timer of given type
 */
int TimerManager::timerLength(GameTimer::TimerType type)
{
    return timers.at(type)->timerLength();
}

/*! Relational value of timer progress.
 *
 * \param type One of \c GameTimer::TimerType game timer enumeration types
 * \return A relational value of timer progress from 0 to 1
 */
GLfloat TimerManager::timeRel(GameTimer::TimerType type)
{
    GameTimer *t = timers.at(type);
    return (GLfloat) t->time() / (GLfloat) t->timerLength();
}

/*! Resets all the timers
 */
void TimerManager::resetTimers()
{
    stopGameTimer(GameTimer::stateGetReadyTimer);
    stopGameTimer(GameTimer::stateLevelChangingTimer);
    stopGameTimer(GameTimer::statePlayerCrashedTimer);
    stopGameTimer(GameTimer::stateGameOverTimer);
    stopGameTimer(GameTimer::shipSafeTimer);
    stopGameTimer(GameTimer::shipBall2ConeTimer);
    stopGameTimer(GameTimer::shipCone2BallTimer);
    stopGameTimer(GameTimer::hyperJumpOutTimer);
    stopGameTimer(GameTimer::hyperJumpInTimer);
    stopGameTimer(GameTimer::bombEffectTimer);
    stopGameTimer(GameTimer::moreObjectsTimer);
}

/*! Cleans all the static effect data
 */
void TimerManager::cleanData()
{
    delete TimerManager::hyperJumpOutData;
    hyperJumpOutData = NULL;
    delete hyperJumpInData;
    hyperJumpInData = NULL;
    delete bombEffectData;
    bombEffectData = NULL;
}
